package com.rzgeo.rzmaplib.model;

import android.content.Context;
import android.content.res.Resources;

import com.esri.arcgisruntime.data.ShapefileFeatureTable;
import com.esri.arcgisruntime.data.TileCache;
import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.geometry.GeometryType;
import com.esri.arcgisruntime.layers.FeatureLayer;
import com.esri.arcgisruntime.symbology.Renderer;
import com.esri.arcgisruntime.symbology.SimpleFillSymbol;
import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
import com.esri.arcgisruntime.symbology.SimpleRenderer;
import com.esri.arcgisruntime.symbology.Symbol;
import com.rzgeo.rzmaplib.R;
import com.rzgeo.rzmaplib.da.RmlDNode;
import com.rzgeo.rzmaplib.da.RmlStdShpNode;
import com.rzgeo.rzmaplib.query.IQuery;
import com.rzgeo.rzmaplib.util.RmlUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by zhanghang on 2018/1/20.
 */

public class RmlPrj extends RmlDNode {

    private final File _dir;
    private final BaseMap _baseMap;
    private final OptionalMap _optionalMap;
    private final EditMap _editMap;
    private State _state;
    private String path;

    public RmlPrj(File f, Context context) {
        super(f.getPath());
        _dir = f;
        _baseMap = new BaseMap(RmlUtil.Files.join(_dir, "底图"));
        _optionalMap = new OptionalMap(RmlUtil.Files.join(_dir, "参考"), context);
        _editMap = new EditMap(RmlUtil.Files.join(_dir, "编辑"), context);
        _state = State.uncheck;
    }

    public static boolean isVaild(File f) {
        if (f.exists() && f.isDirectory())
            return true;
        return false;
    }

    public String getInvestigator() {
        return "未设置";
    }

    public String getBasemapMaker() {
        return "未设置";
    }

    public String getCreateTim() {
        return "2018-01-11";
    }

    public String getEditTim() {
        return RmlUtil.Convert.toStringFromDate(new Date());
    }

    public String getRemark() {
        return "";
    }

    public void getExtent(final IQuery.IOnQueryGeometry onresult) {
        if (_baseMap.doms.length > 0) {
            final TileCache tc = new TileCache(_baseMap.doms[0].getAbsolutePath());
            tc.addDoneLoadingListener(new Runnable() {
                @Override
                public void run() {
                    Envelope extent = tc.getFullExtent();
                    tc.removeDoneLoadingListener(this);
                    onresult.onGeomtry(extent);
                }
            });
            tc.loadAsync();
        } else
            onresult.onFailed("没有找到底图");
    }

    public String getName() {
        return _dir.getName();
    }

    public String getPath() {
        return _dir.getAbsolutePath();
    }

    public BaseMap getBaseMap() {
        return _baseMap;
    }

    public OptionalMap getOptionalMap() {
        return _optionalMap;
    }

    public EditMap getEditMap() {
        return _editMap;
    }

    public long getUID() {
        return 0;
    }

    public State getState() {
        return _state;
    }

    public void release() {

        _baseMap.release();
        _optionalMap.release();
        _editMap.release();
    }

    public boolean checkData(Context context) {
//        return RmlStdShpNode.checkShpForEdit(context,getOptionalMap().shps);
        return true;
    }

    public enum State {
        uncheck("未调查"), checking("调查中"), archived("已归档");
        String _title;

        State(String title) {
            _title = title;
        }

        @Override
        public String toString() {
            return _title;
        }
    }

    public class BaseMap {
        public final File[] doms;
        public final File[] dems;

        public BaseMap(File folder) {
            ArrayList<File> doms = new ArrayList<>();
            ArrayList<File> dems = new ArrayList<>();
            if (folder.exists() && folder.isDirectory()) {
                for (File f : folder.listFiles()) {
                    if (f.getName().toLowerCase().endsWith(".tpk")) {
                        doms.add(f);
                    } else if (f.getName().toLowerCase().endsWith(".tif")) {
                        dems.add(f);
                    }
                }
            }
            this.doms = doms.toArray(new File[0]);
            this.dems = dems.toArray(new File[0]);
        }

        public void release() {

        }
    }

    public class OptionalMap {

        public final File[] shps;
        private final SymbolStack _symbolStack;
        private List<FeatureLayer> _layers = null;

        public OptionalMap(File folder, Context context) {
            _symbolStack = new SymbolStack(context);
            ArrayList<File> shps = new ArrayList<>();
            if (folder.exists() && folder.isDirectory()) {
                for (File f : folder.listFiles()) {
                    if (f.getName().toLowerCase().endsWith(".shp")) {
                        shps.add(f);
                    }
                }
            }
            this.shps = shps.toArray(new File[0]);
        }

        public List<FeatureLayer> getLayers() {
            if (_layers == null) {
                _layers = new ArrayList<>(shps.length);
                for (int i = 0; i < shps.length; i++) {
                    File lFile = shps[i];
                    final ShapefileFeatureTable ft = new ShapefileFeatureTable(lFile.getAbsolutePath());
                    final FeatureLayer fl = new FeatureLayer(ft);
                    fl.setName(lFile.getName());

                    _layers.add(fl);
                }
            }
            return _layers;
        }

        public void release() {
            _layers=null;
        }
    }

    public class EditMap {
        private final SymbolStack _symbolStack;
        private final File _folder;
        private File photoLayerFile;
        private File taskLayerFile;
        private File freeLineLayerFile = null;
        private File markPonLayerFile = null;
        private File markLineLayerFile = null;
        private File markPolygonLayerFile = null;

        private File GpsPonLayerFile = null;
        private File GpsPathLayerFile = null;
        private File[] otherLayerFiles;

        private Map<File, FeatureLayer> _file2Layer;
        private List<FeatureLayer> _layers;

        public void release() {
            _file2Layer.clear();
            _layers=null;
        }

        public EditMap(File folder, Context context) {
            _folder=folder;
            _file2Layer = new HashMap<>();
            _symbolStack = new SymbolStack(context);

            ArrayList<File> otherLayers = new ArrayList<>();
            if (folder.exists() && folder.isDirectory()) {
                for (File f : folder.listFiles()) {
                    if (f.getName().toLowerCase().endsWith("涂鸦.shp")) {
                        this.freeLineLayerFile = f;
                    } else if (f.getName().toLowerCase().endsWith("标记点.shp")) {
                        this.markPonLayerFile = f;
                    } else if (f.getName().toLowerCase().endsWith("编辑线.shp")) {
                        this.markLineLayerFile = f;
                    } else if (f.getName().toLowerCase().endsWith("标记面.shp")) {
                        this.markPolygonLayerFile = f;
                    } else if (f.getName().toLowerCase().endsWith("定位点.shp")) {
                        this.GpsPonLayerFile = f;
                    } else if (f.getName().toLowerCase().endsWith("轨迹.shp")) {
                        this.GpsPathLayerFile = f;
                    } else if (f.getName().toLowerCase().endsWith("目标.shp")) {
                        this.taskLayerFile = f;
                    } else if (f.getName().toLowerCase().endsWith("照片.shp")) {
                        this.photoLayerFile = f;
                    } else if (f.getName().toLowerCase().endsWith(".shp")) {
                        otherLayers.add(f);
                    }
                }
            }
            this.otherLayerFiles = otherLayers.toArray(new File[0]);
        }

        private File[] getAllEditableLayerFiles() {
            File[] standredLayers = new File[]{
                    freeLineLayerFile,
                    markPonLayerFile, markLineLayerFile,
                    markPolygonLayerFile, GpsPonLayerFile, GpsPathLayerFile,
                    taskLayerFile,photoLayerFile};
            ArrayList<File> allLayerFiles = new ArrayList<>();

            for (File fl : standredLayers) {
                if (fl != null)
                    allLayerFiles.add(fl);
            }
            for (File fl : getOtherLayerFiles()) {
                if (fl != null)
                    allLayerFiles.add(fl);
            }
            return allLayerFiles.toArray(new File[0]);
        }


        public File[] getOtherLayerFiles() {
            return otherLayerFiles;
        }

        public FeatureLayer getFreeLineLayer() {
            return _file2Layer.get(freeLineLayerFile);
        }

        public FeatureLayer getMarkPonLayer() {
            return _file2Layer.get(markPonLayerFile);
        }

        public FeatureLayer getMarkLineLayer() {
            return _file2Layer.get(markLineLayerFile);
        }

        public FeatureLayer getMarkolygonLayer() {
            return _file2Layer.get(markPolygonLayerFile);
        }

        public FeatureLayer getGpsPonLayer() {
            return _file2Layer.get(GpsPonLayerFile);
        }

        public FeatureLayer getGpsPathLayer() {
            return _file2Layer.get(GpsPathLayerFile);
        }

        public FeatureLayer getTaskLayer() {
            return _file2Layer.get(taskLayerFile);
        }

        public FeatureLayer getPhotoLayer() {
            return _file2Layer.get(photoLayerFile);
        }

        public List<FeatureLayer> getLayers() {
            if (_layers == null) {
                _layers = new ArrayList<>();

                for (File lFile : getAllEditableLayerFiles()) {
                    final ShapefileFeatureTable ft = new ShapefileFeatureTable(lFile.getAbsolutePath());
                    final FeatureLayer fl = new FeatureLayer(ft);
                    fl.setName(lFile.getName());
                    if (lFile != GpsPonLayerFile &&
                            lFile != markPonLayerFile &&
                            lFile != markLineLayerFile &&
                            lFile != taskLayerFile&&
                            lFile != photoLayerFile) {
                        fl.addDoneLoadingListener(new Runnable() {
                            @Override
                            public void run() {
                                Renderer r = _symbolStack.getRenderer(
                                        fl.getFeatureTable().getGeometryType());
                                fl.setRenderer(r);
                            }
                        });
                        _layers.add(fl);
                    } else {
                        ft.loadAsync();
                        fl.loadAsync();
                    }
                    _file2Layer.put(lFile, fl);
                }
            }
            return _layers;
        }

        public String getPhotoFolder() {
            return _folder+"/照片";
        }
    }

    public static class SymbolStack {

        public static class ColorSet {

            public static class Builder {
                private final Resources _r;

                public Builder(Context context) {
                    _r = context.getResources();
                }

                public ColorSet create(int mainId, int borderId) {
                    return new ColorSet(
                            _r.getColor(mainId),
                            _r.getColor(borderId)
                    );
                }
            }

            public final int main;
            public final int border;

            public ColorSet(int main, int border) {
                this.main = main;
                this.border = border;
            }

            public static void setContext() {

            }
        }

        private int _countSymbol = 0;

        private ColorSet[] _colorSets;

        public SymbolStack(Context context) {
            ColorSet.Builder b = new ColorSet.Builder(context);

            _colorSets = new ColorSet[]{
                    b.create(R.color.rwls_redm, R.color.rwls_redb),
                    b.create(R.color.rwls_greenm, R.color.rwls_greenb),
                    b.create(R.color.rwls_bluem, R.color.rwls_blueb),
                    b.create(R.color.rwls_greym, R.color.rwls_greyb),
                    b.create(R.color.rwls_yellowm, R.color.rwls_yellowb),
                    b.create(R.color.rwls_whitem, R.color.rwls_whiteb),
                    b.create(R.color.rwls_red2m, R.color.rwls_red2b),
                    b.create(R.color.rwls_green2m, R.color.rwls_green2b),
                    b.create(R.color.rwls_blue2m, R.color.rwls_blue2b),
                    b.create(R.color.rwls_grey2m, R.color.rwls_grey2b),
                    b.create(R.color.rwls_yellow2m, R.color.rwls_yellow2b)
            };
        }

        public Renderer getRenderer(GeometryType type) {
            Symbol symbol = null;
            ColorSet cs = _colorSets[_countSymbol];
            switch (type) {
                case POINT:
                    symbol = new SimpleMarkerSymbol(
                            SimpleMarkerSymbol.Style.CROSS,
                            cs.main,
                            4
                    );
                case POLYLINE:
                    symbol = new SimpleLineSymbol(
                            SimpleLineSymbol.Style.SOLID,
                            cs.main,
                            2
                    );
                    break;
                case POLYGON:

                    symbol = new SimpleFillSymbol(
                            SimpleFillSymbol.Style.SOLID,
                            cs.main,
                            new SimpleLineSymbol(
                                    SimpleLineSymbol.Style.DASH,
                                    cs.border,
                                    1)
                    );
                    break;
                case ENVELOPE:


                    symbol = new SimpleFillSymbol(
                            SimpleFillSymbol.Style.BACKWARD_DIAGONAL,
                            cs.main,
                            new SimpleLineSymbol(
                                    SimpleLineSymbol.Style.SOLID,
                                    cs.border,
                                    1)
                    );
                    break;
                case MULTIPOINT:
                    symbol = new SimpleMarkerSymbol(
                            SimpleMarkerSymbol.Style.DIAMOND,
                            cs.main,
                            4
                    );
                    break;
                default:
                    return null;
            }
            _countSymbol++;
            if(_countSymbol==_colorSets.length)
                _countSymbol=0;

            return new SimpleRenderer(symbol);
        }
    }
}
